using System;
using System.Collections.Generic;
using System.Text;
using SubSonic;

using Impact.Model.Objects;
using Impact.Infrastructure.State;
using Impact.Infrastructure.Exceptions;
using StructureMap;
using Impact.Model.Services;

namespace Impact.Model.Service
{
    /// <summary>
    /// data service that provides article data
    /// </summary>
    public class ArticleService : IArticleService
    {

        #region IArticleService Members

        /// <summary>
        /// Retrieve the article object that belongs to the given ID
        /// </summary>
        public Article FetchByID( int articleId )
        {
            return Article.FetchByID( articleId );
        }

        /// <summary>
        /// Retrieve any articles that contain the given terms in their title or bodies
        /// </summary>
        public ArticleCollection FetchByTerms( string terms )
        {
            QueryCommand qc = new QueryCommand( "SELECT * FROM impact_Articles WHERE Enabled='true' AND ( Title LIKE '%'+ @terms +'%' OR Body LIKE '%'+ @terms +'%' )", Databases.ImpactProvider );
            qc.AddParameter( "@terms", terms, System.Data.DbType.String );

            ArticleCollection articles = new ArticleCollection();
            articles.LoadAndCloseReader( DataService.GetReader( qc ) );
            return articles;
        }

        /// <summary>
        /// Retrieve all articles in the given category
        /// </summary>
        /// <param name="categoryId">ID of the category to retrieve</param>
        /// <param name="onlyEnabled">true to return only categories that are enabled.  false to return all categories.</param>
        public ArticleCollection FetchByCategory( int categoryId, bool onlyEnabled )
        {
            ArticleCollection articles = new ArticleCollection()
                .Where( Article.Columns.CategoryId, categoryId )
                .OrderByDesc( Article.Columns.CreatedOn );
            if ( onlyEnabled )
            {
                articles.Where( Article.Columns.Enabled, 1 );
            }
            return articles.Load();
        }

        /// <summary>
        /// Retrieve all articles in the given category
        /// </summary>
        /// <param name="categoryKey">string key of the category to retrieve</param>
        /// <param name="onlyEnabled">true to return only categories that are enabled.  false to return all categories.</param>
        public ArticleCollection FetchByCategory( string categoryKey, bool onlyEnabled )
        {
            ICategoryService categoryService = ObjectFactory.GetInstance<ICategoryService>();
            ArticleCategory category = categoryService.FetchByKey( categoryKey );
            Check.Require( category, "Could not find/load category requested" );

            ArticleCollection articles = new ArticleCollection()
                .Where( Article.Columns.CategoryId, category.CategoryId )
                .OrderByDesc( Article.Columns.CreatedOn );
            if ( onlyEnabled )
            {
                articles.Where( Article.Columns.Enabled, 1 );
            }
            return articles.Load();
        }

        /// <summary>
        /// Commits the given article to the datastore
        /// </summary>
        public void Save( Article article )
        {
            article.Save();
        }

        /// <summary>
        /// Commits the given article to the datastore
        /// </summary>
        public void Save( Article article, Guid guid )
        {
            article.Save( guid );
        }

        /// <summary>
        /// Removes the given article from the datastore
        /// </summary>
        public void Remove( int articleId )
        {
            Article.Delete( articleId );
        }


        /// <summary>
        /// get all the comments for the given article
        /// </summary>
        public ArticleCommentCollection FetchComments( int articleId )
        {
            return new ArticleCommentCollection()
                .Where( ArticleComment.Columns.ArticleId, articleId )
                .OrderByAsc( ArticleComment.Columns.CreatedOn )
                .Load();
        }

        /// <summary>
        /// store the given comment attributing it to the given userID
        /// </summary>
        public void SaveComment( ArticleComment comment, string userId )
        {
            comment.Save( userId );
        }

        /// <summary>
        /// Remove the given comment from it's article
        /// </summary>
        public void RemoveComment( int commentId )
        {
            ArticleComment.Delete( commentId );
        }



        /// <summary>
        /// Retrieve all tags for the given article
        /// </summary>
        public ArticleTagCollection FetchTags( int articleId )
        {
            return new ArticleTagCollection()
                .Where( ArticleTag.Columns.ArticleId, articleId )
                .Load();
        }

        /// <summary>
        /// Adds the given tag to the given article
        /// </summary>
        /// <param name="articleId">ID of the article to attach the tag to</param>
        /// <param name="tagId">ID of the tag to attach</param>
        /// <param name="userId">ID of the user attaching the tag</param>
        public void AddTag( int articleId, int tagId, Guid userId )
        {
            Procedures.CreateArticleTag( articleId, tagId, userId.ToString() ).Execute();
        }

        /// <summary>
        /// Removes the given article-tag relationship
        /// </summary>
        public void RemoveTag( int articleTagId )
        {
            // TODO: add back SP
            //Procedures.DeleteArticleTag(articleTagId).Execute();
        }


        /// <summary>
        /// Removes all tags from the given article
        /// </summary>
        public void RemoveAllTags( int articleId )
        {
            Query q = new Query( "impact_ArticleTags" );
            q.AddWhere( ArticleTag.Columns.ArticleId, articleId );
            QueryCommand qc = q.BuildDeleteCommand();
            DataService.ExecuteQuery( qc );
        }

        /// <summary>
        /// Retrieve all articles
        /// </summary>
        /// <param name="onlyEnabled">retrieve only enabled articles</param>
        /// <returns></returns>
        public ArticleCollection FetchAll( bool onlyEnabled )
        {
            ArticleCollection articles = new ArticleCollection()
                .OrderByDesc( Article.Columns.ModifiedOn );
            if ( onlyEnabled )
            {
                articles.Where( Article.Columns.Enabled, 1 );
            }
            articles.Load();
            return articles;

        }

        #endregion
    }
}
